#ifndef SERIALIZATION_H_
#define SERIALIZATION_H_

#include <string>
#include <sstream>
#include <vector>
#include <list>

#include <windows.h>
#include <winsock2.h>

//#include <boost/archive/text_iarchive.hpp>
//#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>

#include <boost/serialization/string.hpp>

#include "addrinfo.h"

namespace boost {
namespace serialization {

template<class Archive>
void serialize(Archive & ar, struct sockaddr &g, const unsigned int version)
{
	ar & g.sa_family; // ushort
	ar & g.sa_data;// -> void serialize(Archive & ar, const char (&g)[n], const unsigned int version) need optimization
				   // char    sa_data[14];
}

template<class Archive>
void serialize(Archive & ar, SOCKET &g, const unsigned int version)
{
	ar & g;
}

template<class Archive>
void serialize(Archive & ar, struct fd_set &g, const unsigned int version)
{
    ar & g.fd_count;
    ar & g.fd_array;
}

template<class Archive>
void serialize(Archive & ar, struct timeval &g, const unsigned int version)
{
    ar & g.tv_sec;
    ar & g.tv_usec;
}

//template<class Archive>
//void serialize(Archive & ar, WSAOVERLAPPED &g, const unsigned int version)
//{
//    ar & g.Internal;
//    ar & g.InternalHigh;
//    //ar & binary_object(g.);
//    ar & g.hEvent;
//}

template<class Archive>
void serialize(Archive & ar, WSADATA &g, const unsigned int version)
{
    ar & g.wVersion;
    ar & g.wHighVersion;
    
    ar & g.szDescription;
    ar & g.szSystemStatus;
    
    ar & g.iMaxSockets;
    ar & g.iMaxUdpDg;
    
    if (g.wVersion < 2)
    {
        std::string vendorInfo(g.lpVendorInfo);
        ar & vendorInfo;
        //ar & g.lpVendorInfo;
    }
}
template<class Archive>
void serialize(Archive & ar, GUID &g, const unsigned int version)
{
    ar & g.Data1;
    ar & g.Data2;
    ar & g.Data3;
    ar & g.Data4;
}

template<class Archive>
void serialize(Archive & ar, WSAPROTOCOLCHAIN &g, const unsigned int version)
{
    ar & g.ChainLen;
    ar & g.ChainEntries;
}

template<class Archive>
void serialize(Archive & ar, WSAPROTOCOL_INFO &g, const unsigned int version)
{
    ar & g.dwServiceFlags1;
    ar & g.dwServiceFlags2;
    ar & g.dwServiceFlags3;
    ar & g.dwServiceFlags4;
    ar & g.dwProviderFlags;
    ar & g.ProviderId;    
    ar & g.dwCatalogEntryId;
    ar & g.ProtocolChain;
    ar & g.iVersion;
    ar & g.iAddressFamily;
    ar & g.iMaxSockAddr;
    ar & g.iMinSockAddr;
    ar & g.iSocketType;
    ar & g.iProtocol;
    ar & g.iProtocolMaxOffset;
    ar & g.iNetworkByteOrder;
    ar & g.iSecurityScheme;
    ar & g.dwMessageSize;
    ar & g.dwProviderReserved;
    ar & g.szProtocol;
}

} // namespace serialization
} // namespace boost


struct Header {
    DWORD TID_;
    std::string func_name_;

    Header (DWORD TID, const std::string& func_name)
        : TID_(TID), func_name_(func_name)
    {}
    Header (const std::string& func_name)
        : func_name_(func_name)
    {}
    Header(){}

    template<class Archive>    
    void serialize(Archive & ar, const unsigned int )
    {
        ar & TID_;
        ar & func_name_;
    }
    
    bool operator== (const Header& hdr)
    {
        return (this->TID_ == hdr.TID_)
            && (this->func_name_ == hdr.func_name_);
    }
};

template<class T>
void Serialize ( const Header &header, T& func_struct, std::vector<char> &buf )
{
    std::stringstream ss(std::ios_base::in | std::ios_base::out | std::ios_base::binary);
    boost::archive::binary_oarchive oa(ss, 1);

    oa << header; //Write Heder =Func Name + Thread ID
    oa << func_struct;

    std::string tmp_str = ss.str();                         //
    buf.resize(tmp_str.length());                           // Write to Buffer
    std::copy (tmp_str.begin(), tmp_str.end(), buf.begin());//	
}

class Deserialize
{
    Header header_;
    std::vector<char>& buffer_;

    std::stringstream ss;
    boost::archive::binary_iarchive ia;
public:
    Deserialize (std::vector<char>& buf)
        : buffer_(buf), header_(),
          //ss(&(buf.at(0)), std::ios_base::in | std::ios_base::out | std::ios_base::binary),
          ss(std::string(&(buf.at(0)),buf.size()), std::ios_base::in | std::ios_base::out | std::ios_base::binary),
          ia(ss, 1)
    {
        ia >> header_;
    }

    // header will be copied
    Header get_header() const { return header_; }

    template<class T>
    void operator() (T& func_struct)
    {
        ia >> func_struct;
    }
};


#endif /* SERIALIZATION_H_ */